
#ifndef PROJECTZ_USER_H_
#define PROJECTZ_USER_H_

#include "engine.h"
#include "ack.h"
#include "constant.h"

#include <vector>
#include <list>
#include <algorithm>
#include <tr1/memory>
#include <string>

#include <Dispatcher/Timer.h>

#include "Enum.h"
#include "macro.h"
#include "protocol.h"

#include "../../protocol/Cache.h"

#include "NUtil/Pool.h"
#include "NUtil/Single.h"
#include "NUtil/SafeArray.h"

namespace ProjectZ { namespace NLogic {
class QuestInfo;
class Bag;
class Equip;
class Space;
class Party;
class MailBox;
class Trade;
class Buff;
class Status;
class Card;
class SocialInfo;
class BattleAfterEffect;
class VirtualCurrency;
class Score;
class Reward;
class BattleResult;
class BackEndServerInfo;
class Battle;
class UserLocation;
class MemcachedKey;
class Fishing;
class Stamina;
class DailyMission;
class BattleAbility;
} /*NLogic*/ } /*ProjectZ*/

namespace ProjectZ { namespace NLogic { namespace NAsync {
class AsyncTrade;
} /*NAsync*/ } /*NLogic*/ } /*ProjectZ*/

namespace ProjectZ {

class Session;

class User : public ::Dispatcher::Timer::IObserver, public ::Dispatcher::Handler::CPIWrapper, public ::Dispatcher::Handler::ReceiptCheckWrapper, public ::Database::Command::IObserver
{
public:
	// Client 와 공유 중이므로 중간에 값을 추가 하지 말것...
	enum class EnumState {
		__NONE__,

		PVP_QUICK_WAIT = 1,
		PVP_FRIENDLY_WAIT,
		PVP_AMITY_WAIT,
		PVP_READY,	// PVP 준비 상태
		PVP_BATTLE,	// PVP 대전 상태
		PVP_BATTLE_END,

		FRIEND_PARTY_WAIT = 7,	// MASTER
		RANDOM_PARTY_WAIT,	// MASTER

		SINGLE_DUNGEON,

		INVITE = 10,			// OTHER OR FRIEND USER
		ACCEPT_WAIT,
		READY_WAIT,
		DUNGEON_BATTLE,			// 던전에서 전투중..

		BATTLE_ROYAL_PARTY_WAIT = 14,
		BATTLE_ROYAL_READY_WAIT = 15,
		BATTLE_ROYAL_READY = 16,
		BATTLE_ROYAL_BATTLE = 17,
		BATTLE_ROYAL_END = 18,

		RECONNECT_WAIT,

		RECALL,

		PHYSICAL_CHANGE,

		TUTORIAL,

		NEW_PVP_ROOM_WAIT,

		WORLDBOSS_SINGLE,
		WORLDBOSS_PARTY,

		ENTER_EVENT_DUNGEON,

		RECEIPT_CHECKING_CLOSE,

		__MAX__
	};

	enum class TimerID {
		__NONE_,
		NOTRESPONSE,
		DISCONNECT,
		__MAX__,
	};

public:
	class Factory : public NUtil::Single<Factory>
	{
	public:
		Factory();
		~Factory();
		User *		NEW();
		bool 		DEL(User * pUser);
	private:
		NUtil::Pool<User> * pPool;
	};
public:
	class State
	{
	public:
		State();
		virtual ~State();
		typedef void(* Command)(User * pUser, ::Network::Packet * pPacket);
		Command 			GetCommand(unsigned short cmd);
		std::string &		GetName();
		virtual void		OnClose(User * pUser, bool bForceClose) = 0;
		virtual void 		OnResponse(::Database::Command* pCommand) {};
	protected:
		bool 				AddCommand(unsigned short cmd, Command pCommand);
	protected:
		std::map<int, Command> 	clsCommandMap;
		std::string				_name;
	};

public:
	User();
	virtual ~User();

	virtual void 	Initialize();
	virtual void 	Finalize();

	void	Send(::Network::Packet *pPacket, bool printhex=false);
	void	SendOneshotEncrypt(::Network::Packet *pPacket, bool printhex=false);

	void	SetCoordinate(int x, int y, int degree=0);
	void	Set_PK_Coordinate(int x, int y, int degree=0);

	void			IncreaseRefCount();
	void			DecreaseRefCount();
	void			DecreaseRefCount_PhysicalChange();
	unsigned int	GetRefCount();

public:
	typedef std::vector<NLogic::Bag *> BAGVECTOR;
	typedef std::vector<int>				VECTORINFO;


private:
	std::string 	_socialID;
	std::string	_userNickName;
	std::string	_uuid;

	uint32_t		_company;
	uint32_t		_sale_code;

	// UserInfo, CharacterInfo 에 사용하지 않은 항목을 사용 시 Cache.idl or doc/readme.txt 파일 참고
	UserInfo 		_userInfo;
	CharacterInfo _characterInfo[8];
	std::vector<time_t>	_dailyEPTime;
	int				_userSeq;
	int				_encrypt_key;
	bool			_userInfoCache;
	bool			_characterInfoCache;
	bool			_locationRegist;
	bool			_bagInfoCache;
	bool			_bDisconnect;
	int 			_openCharacterCount;
	int 			_loadCharacterCount;

	BAGVECTOR		_clsBagVector;

	NLogic::Equip *		_equip;
	NLogic::Buff *		_buff;
	NLogic::Status *		_status;
	NLogic::Card *		_card;
	NLogic::SocialInfo * _socialInfo;
	NLogic::MailBox *	_mailBox;
	NLogic::BattleAfterEffect * _battleAfterEffect;
	NLogic::VirtualCurrency *	_virtualCurrency;
	NLogic::Score *		_score;
	NLogic::Reward *		_reward;
	NLogic::BattleResult * _battleResult;
	NLogic::UserLocation * _userLocation;
	NLogic::Trade *		_trade;
	NLogic::MemcachedKey * _memKey;
	NLogic::BackEndServerInfo * _backEndServerInfo;
	NLogic::QuestInfo *	_questInfo;
	NLogic::Fishing * _fishing;
	NLogic::Stamina * _stamina;
	NLogic::DailyMission	* _dailyMission;
	NLogic::BattleAbility	* _battleAbility;
	NLogic::NAsync::AsyncTrade	* _asyncTrade;

	State *			_state;
	Session *			_session;

	bool				_bClose;
	bool				_bDelUser;
	bool				_bZENEvent;
	bool				_bBattleReconnect;
	NLogic::Space *	_space;
	NLogic::Space *	_world;
	NLogic::Space *	_reserveSpace;
	int 				_worldIndex;
	NLogic::Battle *	_battle;

	EnumState			_enumStateType;
	NLogic::Party *	_party;
	bool				_partyAccept;

//	std::vector<int>	_array_dungeon_clear_info;
//	std::vector<int>	_array_dungeon_clear_point;
//	std::vector<int>	_array_bag_order_info;
	bool				_battle_aftereffect;

	unsigned long		_latency;

	unsigned int		_refCount;
	time_t				_characterInfoSetTime;
	time_t				_loginTime;

	int					_guildGrade;
	std::string			_guildName;

public:
	void 				SetSocialID(const char * socialID) { _socialID = socialID; }
	std::string &		GetSocialID() { return _socialID; }

	void 				SetUserNickName(const char * nickName) { _userNickName = nickName; }
	std::string &		GetUserNickName() { return _userNickName; }

	void 				Setuuid(const char * uuid) { _uuid = uuid; }
	std::string &		Getuuid() { return _uuid; }

	void				SetCompany(uint32_t company) { _company = company; }
	uint32_t			GetCompany() { return _company; }

	void				SetSaleCode(uint32_t sale_code) { _sale_code = sale_code; }
	uint32_t			GetSaleCode() { return _sale_code; }

	void 				SetUserInfo(UserInfo & userInfo);
	UserInfo &			GetUserInfo() { return _userInfo; }

	void 				SetCharacterInfo(CharacterInfo & characterInfo, int slotIndex);
	CharacterInfo &	GetCharacterInfo() { return _characterInfo[_userInfo.main_slot_index]; }
	CharacterInfo &	GetCharacterInfoFromIndex(int index) { return _characterInfo[index]; }

	void 				SetUserSeq(int userSeq);// { _userSeq = userSeq; }
	int					GetUserSeq() { return _userSeq; }

	void				SetGuildSeq(uint32_t seq ) { _userInfo.guild_seq = seq; }
	uint32_t			GetGuildSeq() { return _userInfo.guild_seq; }

	void 				SetEncryptKey(int ecriptKey) { _encrypt_key = ecriptKey; }
	int					GetEncryptKey() { return _encrypt_key; }

	void				SetGuildGrade(int grade) { _guildGrade = grade; }
	int					GetGuildGrade() { return _guildGrade; }

	void				SetGuildName(const char * guildName) { _guildName = guildName; }
	std::string &		GetGuildName() { return _guildName; }

	void				SetLocationRegist();
	void				SetCharacterInfoSetTime(time_t characterInfoSetTime);
	time_t				GetCharacterInfoSetTime();

	void				SetLoginTime(time_t loginTime);
	time_t				GetLoginTime();

	void				SetAllDailyEPTime(time_t settime);
	void				SetDailyEPTime(time_t settime);
	time_t				GetDailyEPTime();

	void				SetOpenCharacterCount(int count) { _openCharacterCount = count; }
	int 				GetOpenCharacterCount() { return _openCharacterCount; }
	void				AddOpenCharacterCount() { _openCharacterCount++; }

	void				AddLoadCharacterCount() { _loadCharacterCount++; }
	int 				GetLoadCharacterCount() { return _loadCharacterCount; }

	void				CacheBagInfo(bool bFlag) { _bagInfoCache = bFlag; }
	bool				IsCacheBagInfo() { return _bagInfoCache; }

	void				SetDisconnectStatus(bool bFlag) { _bDisconnect = bFlag; }
	bool				GetDisconnectStatus() { return _bDisconnect; }

	void 				FlushUserInfo();
	void 				FlushCharacterInfo();
	void 				FlushNewCharacterInfo(int slotindex);
	void				UnRegistLocation();

	void				FlushUserInfoCache();
	void	 			FlushCharacterInfoCache();

	NLogic::Bag *					GetBag(INVEN_BAG_TYPE eBagType);
	NLogic::Equip *				GetEquip();
	NLogic::Battle *				GetBattle();
	NLogic::MailBox *				GetMailBox();
	NLogic::Trade *				GetTrade();
	NLogic::Buff *				GetBuff();
	NLogic::Status *				GetStatus();
	NLogic::Card *				GetCard();
	NLogic::SocialInfo *			GetSocialInfo();
	NLogic::BattleAfterEffect * GetBattleAfterEffect();
	NLogic::VirtualCurrency *	GetVirtualCurrency();
	NLogic::Score *				GetScore();
	NLogic::Reward *				GetReward();
	NLogic::BattleResult *		GetBattleResult();
	NLogic::UserLocation *		GetUserLocation();
	NLogic::MemcachedKey *		GetMemKey();
	NLogic::BackEndServerInfo *	GetBackEndServerInfo();
	NLogic::QuestInfo *			GetQuestInfo();
	NLogic::Fishing *			GetFishing();
	NLogic::Stamina *			GetStamina();
	NLogic::DailyMission *		GetDailyMission();
	NLogic::BattleAbility *		GetBattleAbility();
	NLogic::NAsync::AsyncTrade *	GetAsyncTrade();

	bool				GiveBaseItem(int slotIndex);

	void				SetState(State * state);
	State *			GetState() { return _state; }

	void 				SetSession(Session * pSession) { _session = pSession; }
	Session *			GetSession() { return _session; }

	//void				SetClose() { _bClose = true; }
	void				SetDelUser(){ _bDelUser = true; }
	bool				GetDelUser() { return _bDelUser; }

	void				SetSpace(NLogic::Space * space);
	NLogic::Space *	GetSpace();
	void				SetReserveSpace(NLogic::Space * pSpace);
	NLogic::Space *	GetReserveSpace();

	void				_setWorldSpace(NLogic::Space * world) { _world = world; }
	NLogic::Space *	_getWorldSpace() { return _world; }

	int					GetOldWorldSpaceIndex() { return _worldIndex; }

	void				SetEnumState(EnumState state);// { _Pre_enumStateType = _enumStateType; _enumStateType = state; }
	EnumState			GetEnumState() { return _enumStateType; }

	void				SetParty(NLogic::Party * pParty) { _party = pParty; }
	NLogic::Party *	GetParty() { return _party; }

	void				SetPartyAccept() { _partyAccept = true; }
	bool				GetPartyAccept() { return _partyAccept; }

	void				OnDisconnect();
	void 				OnReconnect();
	// 유저에 데이터를 정리처리....
	void				CleanUp();
	void				ForceCleanUp();
	void				PhysicalChangeCleanUp();
	bool 				OnTime(int id, void* param);
	void				OnCPI();
	void				OnReceiptCheck();
	virtual void		OnResponse(::Database::Command * pCommand);
	virtual void		OnError(::Database::Command * pCommand, const char* err, int errCode);

//	VECTORINFO &		Get_array_dungeon_clear_info() { return _array_dungeon_clear_info; }
//	VECTORINFO &		Get_array_dungeon_clear_point() { return _array_dungeon_clear_point; }
//
//	BAG_ORDER &		Get_array_bag_order_info() { return _clsBagOrder; }


	void				PreFlush();

	void				SetBattle_afterEffect();
	void				CancelBattle_afterEffect();
	bool				EndBattle_afterEffect();

	void				SetPVPBattleResult_afterEffect();
	void				SetPKBattleResult_afterEffect();

	void 				UpdateLatency();
	unsigned long		GetLastLatency();
	
	void 				ChangeMainSlot();

	void					SetBattleRoyalBattle(NLogic::Battle * pBattle) { _battleRoyalBattle = pBattle; }
	NLogic::Battle *		GetBattleRoyalBattle() { return _battleRoyalBattle; }

	void				SetZENEventFlag();
	bool				GetZENEventFlag();

private:
	NLogic::Battle *	_battleRoyalBattle;

private:
	void				load_DungeonClear_BagOrder_Buff_BattleAfterEffect();
	void				save_DungeonClear_BagOrder_Buff_BattleAfterEffect();
	void				load_Daily_Mission_Info();
	void				save_Daily_Mission_Info();


protected:
	int		GID;

public:
	void 				SetLogin();
	bool				GetLogin()  {return _login; }

	void				SetVersion(int version) { _version = version; }
	int 				GetVersion() { return _version; }
private:
	bool				_login;
	int					_version;


public:
	void				SetKick() { _isKick = true; }
private:
	bool				_isKick;

public:
	int 				SubRefCount() { return --_refCount; }

	void				SetCharacterInfoCache() { _characterInfoCache = true; }

public:
	void				RewindState();
	void				RewindEnumState();
private:
	std::list<State * >		_clsStateHistory;
	std::list<EnumState> 	_clsEnumStateHistory;

public:
	void				SetLoadBagTypeSeq(int bagTypeSeq) { _loadBagTypeSeq = bagTypeSeq; }
	int					GetLoadBatTypeSeq() { return _loadBagTypeSeq; }
private:
	int					_loadBagTypeSeq;

public:
	typedef NUtil::SafeArray<int, static_cast<int>(MAX_DUNGEON_COUNT)> 	DUNGEON_CREAR_INFO;
	typedef NUtil::SafeArray<int, static_cast<int>(MAX_DUNGEON_COUNT)> 	DUNGEON_CREAR_POINT;
	typedef NUtil::SafeArray<int, static_cast<int>(BAG_TYPE_MAX)> 			BAG_ORDER;

	DUNGEON_CREAR_INFO &		GetDungeonClearInfo() { return _clsDungeonClearInfo; }
	DUNGEON_CREAR_POINT &	GetDungeonClearPoint() { return _clsDungeonClearPoint; }
	BAG_ORDER &				GetBagOrder() { return _clsBagOrder; }
private:
	DUNGEON_CREAR_INFO	_clsDungeonClearInfo;
	DUNGEON_CREAR_POINT	_clsDungeonClearPoint;
	BAG_ORDER				_clsBagOrder;

public:
	void					SetCacheFail() { _userInfoCache = false; _characterInfoCache = false; }

public:
	void					AddSerial() { _serial++; if (300 == _serial) _serial = 1;}
	void					ResetSerial() { _serial = 1; }
	int 					GetSerial() { return _serial; }
private:
	int						_serial;

public:
	void					CheckChief();
	
public:
	void					SetDeadTime(unsigned long _now) { _lastDeadTime = _now; }
	unsigned long			GetDeadTime() { return _lastDeadTime; }
private:
	unsigned long			_lastDeadTime;	

public:
	void 					SetVehicleState(int state) { vehicle_state = state; }
	int						GetVehicleState() { return vehicle_state; }
private:
	int 					vehicle_state;

};

} /* namespace ProjectZ */

#endif /* PROJECTZ_USER_H_ */
